home *** CD-ROM | disk | FTP | other *** search
/ AMIGA-CD 2 / Amiga-CD - Volume 2.iso / gepackte_disketten / 1994 / 08_94_5.dms / 08_94_5.adf / term-4.0-Source.lha / termBuffer.c < prev    next >
C/C++ Source or Header  |  1994-06-27  |  21KB  |  1,092 lines

  1. /*
  2. **    termBuffer.c
  3. **
  4. **    Auxilary routines for text buffer/capture management.
  5. **
  6. **    Copyright © 1990-1994 by Olaf `Olsen' Barthel
  7. **        All Rights Reserved
  8. */
  9.  
  10. #include "termGlobal.h"
  11.  
  12.     /* Search string window gadgets. */
  13.  
  14. enum    {    GAD_STRING,GAD_FORWARD,GAD_OK,GAD_CANCEL };
  15.  
  16.     /* Maximum size of an allocated line string. */
  17.  
  18. #define STRING_SIZE    (1 + 255 + 1)
  19.  
  20.     /* How many strings to include in a single puddle. */
  21.  
  22. #define STRING_COUNT    10
  23.  
  24.     /* The number of lines the buffer will grow. */
  25.  
  26. #define BUFFER_GROW    100
  27.  
  28.     /* Memory pool header. */
  29.  
  30. STATIC APTR        BufferPoolHeader;
  31.  
  32.     /* AllocString(STRPTR String,WORD Len):
  33.      *
  34.      +    Allocate space for a string, new pooled version.
  35.      */
  36.  
  37. STATIC STRPTR __regargs
  38. AllocString(STRPTR String,LONG Len)
  39. {
  40.     STRPTR Mem;
  41.  
  42.     if(Len > 255)
  43.         Len = 255;
  44.  
  45.     if(Mem = (STRPTR)LibAllocPooled(BufferPoolHeader,1 + Len + 1))
  46.     {
  47.         *Mem++ = Len;
  48.  
  49.         CopyMem(String,Mem,Len);
  50.  
  51.         Mem[Len] = 0;
  52.  
  53.         return((STRPTR)Mem);
  54.     }
  55.     else
  56.         return(NULL);
  57. }
  58.  
  59.     /* FreeString(STRPTR String):
  60.      *
  61.      *    Free the space occupied by a string, new pooled version.
  62.      */
  63.  
  64. STATIC VOID __regargs
  65. FreeString(STRPTR String)
  66. {
  67.     LibFreePooled(BufferPoolHeader,&String[-1],1 + String[-1] + 1);
  68. }
  69.  
  70.     /* AddLine(STRPTR Line,LONG Size):
  71.      *
  72.      *    Add a line to the display buffer.
  73.      */
  74.  
  75. STATIC VOID __regargs
  76. AddLine(register STRPTR Line,register LONG Size)
  77. {
  78.         /* Are we still to update the buffer contents? */
  79.  
  80.     if(!BufferClosed)
  81.     {
  82.             /* Remove trailing spaces. */
  83. /*
  84.         while(Size > 0 && Line[Size - 1] == ' ')
  85.             Size--;
  86. */
  87.             /* Is the buffer array initialized? */
  88.  
  89.         if(BufferLines)
  90.         {
  91.             ULONG Signals = 0;
  92.  
  93.                 /* Pick up the global access semaphore
  94.                  * (two tasks are sharing the data).
  95.                  */
  96.  
  97.             ObtainSemaphore(BufferSemaphore);
  98.  
  99.                 /* Check for limit. */
  100.  
  101.             if(Config -> CaptureConfig -> MaxBufferSize && BufferSpace >= Config -> CaptureConfig -> MaxBufferSize)
  102.             {
  103.                 register LONG i;
  104.  
  105.                 BufferSpace -= BufferLines[0][-1];
  106.  
  107.                 FreeString(BufferLines[0]);
  108.  
  109.                 for(i = 1 ; i < MaxLines ; i++)
  110.                     BufferLines[i - 1] = BufferLines[i];
  111.  
  112.                 Lines--;
  113.  
  114.                     /* Tell the buffer task to
  115.                      * refresh the display.
  116.                      */
  117.  
  118.                 Signals = SIG_MOVEUP;
  119.             }
  120.             else
  121.             {
  122.                     /* We've reached the last line in the buffer. */
  123.  
  124.                 if(Lines == MaxLines)
  125.                 {
  126.                     STRPTR *MoreBuffer;
  127.  
  128.                         /* Allocate space for some more lines. */
  129.  
  130.                     if(MoreBuffer = (STRPTR *)AllocVecPooled((MaxLines + BUFFER_GROW) * sizeof(STRPTR),MEMF_ANY | MEMF_CLEAR))
  131.                     {
  132.                         register LONG i;
  133.  
  134.                         BufferChanged = TRUE;
  135.  
  136.                             /* Copy the old lines to the new
  137.                              * buffer.
  138.                              */
  139.  
  140.                         for(i = 0 ; i < Lines ; i++)
  141.                             MoreBuffer[i] = BufferLines[i];
  142.  
  143.                             /* Free the old lines. */
  144.  
  145.                         FreeVecPooled(BufferLines);
  146.  
  147.                             /* Set the new buffer. */
  148.  
  149.                         MaxLines += BUFFER_GROW;
  150.  
  151.                         BufferLines = MoreBuffer;
  152.                     }
  153.                     else
  154.                     {
  155.                         BufferChanged = TRUE;
  156.  
  157.                             /* We couldn't get enough memory
  158.                              * to extend the number of lines
  159.                              * in the buffer, so we'll have
  160.                              * to wrap the contents of the
  161.                              * buffer around.
  162.                              */
  163.  
  164.                         if(Lines)
  165.                         {
  166.                             register LONG i;
  167.  
  168.                             BufferSpace -= BufferLines[0][-1];
  169.  
  170.                             FreeString(BufferLines[0]);
  171.  
  172.                             for(i = 1 ; i < MaxLines ; i++)
  173.                                 BufferLines[i - 1] = BufferLines[i];
  174.  
  175.                             Lines--;
  176.  
  177.                                 /* Tell the buffer task to
  178.                                  * refresh the display.
  179.                                  */
  180.  
  181.                             Signals = SIG_MOVEUP;
  182.                         }
  183.                     }
  184.                 }
  185.             }
  186.  
  187.                 /* Allocate a new line and copy the buffer contents
  188.                  * into it.
  189.                  */
  190.  
  191.             if(BufferLines[Lines] = AllocString(Line,Size))
  192.             {
  193.                 BufferChanged = TRUE;
  194.  
  195.                 Lines++;
  196.  
  197.                 BufferSpace += Size;
  198.             }
  199.  
  200.             ReleaseSemaphore(BufferSemaphore);
  201.  
  202.                 /* Tell the buffer task to update the display. */
  203.  
  204.             if(!Signals)
  205.             {
  206.                 Signals = SIG_UPDATE;
  207.  
  208.                 UpdateReview(FALSE);
  209.             }
  210.             else
  211.                 UpdateReview(TRUE);
  212.  
  213.             ObtainSemaphore(&BufferTaskSemaphore);
  214.  
  215.             if(BufferTask && Signals)
  216.             {
  217.                 Forbid();
  218.  
  219.                 ClrSignal(SIG_HANDSHAKE);
  220.  
  221.                 Signal(BufferTask,Signals);
  222.  
  223.                 Wait(SIG_HANDSHAKE);
  224.  
  225.                 Permit();
  226.             }
  227.  
  228.             ReleaseSemaphore(&BufferTaskSemaphore);
  229.         }
  230.     }
  231. }
  232.  
  233.     /* StoreBuffer(APTR Buffer,LONG Size):
  234.      *
  235.      *    Store data in the display buffer.
  236.      */
  237.  
  238. VOID __regargs
  239. StoreBuffer(register STRPTR Buffer,register LONG Size)
  240. {
  241.     STATIC UBYTE __far    LineBuffer[BUFFER_LINE_MAX + 1];
  242.     STATIC LONG          BufferCount = 0;
  243.  
  244.     register UBYTE c;
  245.  
  246.     while(Size--)
  247.     {
  248.             /* Look which char we are to handle. */
  249.  
  250.         switch(c = *Buffer++)
  251.         {
  252.                 /* Move the cursor one step back. */
  253.  
  254.             case BKS:
  255.  
  256.                 if(BufferCount)
  257.                     BufferCount--;
  258.  
  259.                 break;
  260.  
  261.                 /* Move the cursor to the next tab
  262.                  * stop.
  263.                  */
  264.  
  265.             case TAB:
  266.  
  267.                 if(((BufferCount + 8) & ~7) < LastColumn)
  268.                 {
  269.                     register LONG Delta = ((BufferCount + 8) & ~7) - BufferCount;
  270.  
  271.                     memset(&LineBuffer[BufferCount],' ',Delta);
  272.  
  273.                     BufferCount += Delta;
  274.                 }
  275.                 else
  276.                 {
  277.                     AddLine(LineBuffer,BufferCount);
  278.  
  279.                     BufferCount = 0;
  280.                 }
  281.  
  282.                 break;
  283.  
  284.                 /* Terminate the current line. */
  285.  
  286.             case ENT:
  287.  
  288.                 AddLine(LineBuffer,BufferCount);
  289.  
  290.                 BufferCount = 0;
  291.  
  292.                 break;
  293.  
  294.                 /* Stuff the character into the buffer. */
  295.  
  296.             default:
  297.  
  298.                 if(Config -> TerminalConfig -> FontMode == FONT_STANDARD)
  299.                 {
  300.                     if(IsPrintable[c])
  301.                         LineBuffer[BufferCount++] = c;
  302.                 }
  303.                 else
  304.                 {
  305.                     if(c)
  306.                         LineBuffer[BufferCount++] = c;
  307.                 }
  308.  
  309.                 break;
  310.         }
  311.  
  312.             /* The line is full, add it to the display buffer. */
  313.  
  314.         if(BufferCount >= LastColumn || BufferCount == Config -> CaptureConfig -> BufferWidth)
  315.         {
  316.             AddLine(LineBuffer,BufferCount);
  317.  
  318.             BufferCount = 0;
  319.         }
  320.     }
  321. }
  322.  
  323.     /* DeleteBuffer():
  324.      *
  325.      *    Delete buffer resources.
  326.      */
  327.  
  328. VOID
  329. DeleteBuffer()
  330. {
  331.     if(BufferLines)
  332.     {
  333.         FreeVecPooled(BufferLines);
  334.  
  335.         BufferLines = NULL;
  336.     }
  337.  
  338.     if(BufferPoolHeader)
  339.     {
  340.         LibDeletePool(BufferPoolHeader);
  341.  
  342.         BufferPoolHeader = NULL;
  343.     }
  344.  
  345.     if(BufferSemaphore)
  346.     {
  347.         FreeVecPooled(BufferSemaphore);
  348.  
  349.         BufferSemaphore = NULL;
  350.     }
  351. }
  352.  
  353.     /* CreateBuffer():
  354.      *
  355.      *    Allocate buffer resources.
  356.      */
  357.  
  358. BYTE
  359. CreateBuffer()
  360. {
  361.     if(BufferLines = (STRPTR *)AllocVecPooled(MaxLines * sizeof(STRPTR),MEMF_ANY | MEMF_CLEAR | MEMF_PUBLIC))
  362.     {
  363.         if(BufferSemaphore = (struct SignalSemaphore *)AllocVecPooled(sizeof(struct SignalSemaphore),MEMF_ANY | MEMF_PUBLIC))
  364.         {
  365.             InitSemaphore(BufferSemaphore);
  366.  
  367.                 /* Create a memory pool header if possible. */
  368.  
  369.             if(BufferPoolHeader = LibCreatePool(MEMF_ANY | MEMF_PUBLIC,STRING_SIZE * STRING_COUNT,STRING_SIZE * STRING_COUNT))
  370.                 return(TRUE);
  371.         }
  372.  
  373.         FreeVecPooled(BufferLines);
  374.  
  375.         BufferLines = NULL;
  376.     }
  377.  
  378.     return(FALSE);
  379. }
  380.  
  381.     /* FreeBuffer():
  382.      *
  383.      *    Release the contents of the text buffer.
  384.      */
  385.  
  386. VOID
  387. FreeBuffer()
  388. {
  389.         /* Free the contents of the display buffer. */
  390.  
  391.     if(BufferLines)
  392.     {
  393.         APTR NewPoolHeader;
  394.  
  395.             /* If a new pool header is available, free the old
  396.              * pool and replace it with the new pool.
  397.              */
  398.  
  399.         if(NewPoolHeader = LibCreatePool(MEMF_ANY | MEMF_PUBLIC,STRING_SIZE * STRING_COUNT,STRING_SIZE * STRING_COUNT))
  400.         {
  401.             LibDeletePool(BufferPoolHeader);
  402.  
  403.             BufferPoolHeader = NewPoolHeader;
  404.         }
  405.         else
  406.         {
  407.             LONG i;
  408.  
  409.             for(i = 0 ; i < Lines ; i++)
  410.             {
  411.                 if(BufferLines[i])
  412.                     FreeString(BufferLines[i]);
  413.             }
  414.         }
  415.  
  416.         FreeVecPooled(BufferLines);
  417.  
  418.         Lines = 0;
  419.  
  420.         MaxLines = BUFFER_GROW;
  421.  
  422.         BufferLines = (STRPTR *)AllocVecPooled(MaxLines * sizeof(STRPTR),MEMF_ANY | MEMF_CLEAR);
  423.  
  424.         UpdateReview(TRUE);
  425.     }
  426.  
  427.     BufferSpace = 0;
  428.  
  429.     BufferChanged = FALSE;
  430. }
  431.  
  432.     /* DeleteSearchInfo(struct SearchInfo *Info):
  433.      *
  434.      *    Free buffer allocated by CreateSearchInfo().
  435.      */
  436.  
  437. VOID __regargs
  438. DeleteSearchInfo(struct SearchInfo *Info)
  439. {
  440.     if(Info)
  441.         FreeVecPooled(Info);
  442. }
  443.  
  444.     /* CreateSearchInfo(STRPTR Pattern):
  445.      *
  446.      *    Create auxilary data required by SearchTextBuffer().
  447.      */
  448.  
  449. struct SearchInfo * __regargs
  450. CreateSearchInfo(STRPTR Pattern,BOOLEAN Forward,BOOLEAN IgnoreCase)
  451. {
  452.     struct SearchInfo *Info;
  453.  
  454.         /* Allocate the buffer. */
  455.  
  456.     if(Info = (struct SearchInfo *)AllocVecPooled(sizeof(struct SearchInfo),MEMF_ANY | MEMF_PUBLIC))
  457.     {
  458.         WORD i;
  459.  
  460.             /* Determine pattern width. */
  461.  
  462.         Info -> PatternWidth    = strlen(Pattern);
  463.         Info -> IgnoreCase    = IgnoreCase;
  464.  
  465.             /* Turn the pattern into upper case characters. */
  466.  
  467.         if(IgnoreCase)
  468.         {
  469.             for(i = 0 ; i <= Info -> PatternWidth ; i++)
  470.                 Info -> Pattern[i] = ToUpper(Pattern[i]);
  471.         }
  472.         else
  473.         {
  474.             for(i = 0 ; i <= Info -> PatternWidth ; i++)
  475.                 Info -> Pattern[i] = Pattern[i];
  476.         }
  477.  
  478.             /* Fill the entire range with the maximum pattern width. */
  479.  
  480.         for(i = 0 ; i < 256 ; i++)
  481.             Info -> Distance[i] = Info -> PatternWidth;
  482.  
  483.             /* Fill in the matching distances. */
  484.  
  485.         if(Forward)
  486.         {
  487.             for(i = 0 ; i < Info -> PatternWidth - 1 ; i++)
  488.                 Info -> Distance[Info -> Pattern[i]] = Info -> PatternWidth - 1 - i;
  489.         }
  490.         else
  491.         {
  492.             for(i = Info -> PatternWidth - 1 ; i > 0 ; i--)
  493.                 Info -> Distance[Info -> Pattern[i]] = i;
  494.         }
  495.  
  496.             /* Restart from scratch. */
  497.  
  498.         Info -> FoundY    = -1;
  499.         Info -> Forward    = Forward;
  500.     }
  501.  
  502.     return(Info);
  503. }
  504.  
  505.     /* SearchTextBuffer():
  506.      *
  507.      *    String search function, based on the Boyer-Moore search
  508.      *    algorithm.
  509.      */
  510.  
  511. LONG __regargs
  512. SearchTextBuffer(struct SearchInfo *Info)
  513. {
  514.     if(BufferLines)
  515.     {
  516.         UBYTE    *Distance,
  517.             *Pattern;
  518.         WORD    LineWidth,
  519.             PatternWidth;
  520.         STRPTR    Line;
  521.  
  522.         LONG    i;
  523.         WORD    SearchPosition,PatternIndex,LineIndex,LastSearchPosition;
  524.  
  525.             /* Extract the relevant data. */
  526.  
  527.         Distance    = Info -> Distance;
  528.         Pattern        = Info -> Pattern;
  529.         PatternWidth    = Info -> PatternWidth;
  530.  
  531.             /* Which direction are we to search? */
  532.  
  533.         if(Info -> IgnoreCase)
  534.         {
  535.             if(Info -> Forward)
  536.             {
  537.                     /* Update the search positions. */
  538.  
  539.                 if(Info -> FoundY == -1)
  540.                 {
  541.                     Info -> FoundX        = 0;
  542.                     Info -> FoundY        = 0;
  543.                     LastSearchPosition    = 0;
  544.                 }
  545.                 else
  546.                 {
  547.                         /* Proceed to the next line. */
  548.  
  549.                     if(!(LastSearchPosition = Info -> Index))
  550.                         Info -> FoundY = (Info -> FoundY + 1) % Lines;
  551.                 }
  552.  
  553.                     /* Run down the buffer. */
  554.  
  555.                 for(i = Info -> FoundY ; i < Lines ; i++)
  556.                 {
  557.                     Line = BufferLines[i];
  558.  
  559.                         /* Is there anything to search for? */
  560.  
  561.                     if((LineWidth = Line[-1]) >= PatternWidth)
  562.                     {
  563.                             /* Where are we to start searching? */
  564.  
  565.                         if(LastSearchPosition)
  566.                             SearchPosition = LastSearchPosition;
  567.                         else
  568.                             SearchPosition = PatternWidth;
  569.  
  570.                         do
  571.                         {
  572.                                 /* How many line characters
  573.                                  * match the pattern?
  574.                                  */
  575.  
  576.                             PatternIndex    = PatternWidth - 1;
  577.                             LineIndex    = SearchPosition - 1;
  578.  
  579.                             while(PatternIndex >= 0 && Pattern[PatternIndex] == ToUpper(Line[LineIndex]))
  580.                             {
  581.                                 LineIndex--;
  582.                                 PatternIndex--;
  583.                             }
  584.  
  585.                                 /* Update the line search index
  586.                                  * for subsequent searches.
  587.                                  */
  588.  
  589.                             SearchPosition += Distance[ToUpper(Line[SearchPosition - 1])];
  590.  
  591.                                 /* Found the pattern? */
  592.  
  593.                             if(PatternIndex < 0)
  594.                             {
  595.                                     /* Store the position. */
  596.  
  597.                                 Info -> FoundX    = LineIndex + 1;
  598.                                 Info -> FoundY    = i;
  599.  
  600.                                     /* Remember column to start
  601.                                      * next search attempt at.
  602.                                      */
  603.  
  604.                                 if(SearchPosition <= LineWidth)
  605.                                     Info -> Index = SearchPosition;
  606.                                 else
  607.                                     Info -> Index = 0;
  608.  
  609.                                 return(i);
  610.                             }
  611.                         }
  612.                         while(SearchPosition <= LineWidth);
  613.                     }
  614.  
  615.                         /* Reset search column. */
  616.  
  617.                     LastSearchPosition = 0;
  618.                 }
  619.             }
  620.             else
  621.             {
  622.                     /* Update the search positions. */
  623.  
  624.                 if(Info -> FoundY == -1)
  625.                 {
  626.                     Info -> FoundX        = 0;
  627.                     Info -> FoundY        = Lines - 1;
  628.                     LastSearchPosition    = 0;
  629.                 }
  630.                 else
  631.                 {
  632.                     if((LastSearchPosition = Info -> Index) < 1)
  633.                     {
  634.                         if(Info -> FoundY)
  635.                             Info -> FoundY--;
  636.                         else
  637.                             Info -> FoundY = Lines - 1;
  638.                     }
  639.                 }
  640.  
  641.                     /* Run down the buffer. */
  642.  
  643.                 for(i = Info -> FoundY ; i >= 0 ; i--)
  644.                 {
  645.                     Line = BufferLines[i];
  646.  
  647.                         /* Is there anything to search for? */
  648.  
  649.                     if((LineWidth = Line[-1]) >= PatternWidth)
  650.                     {
  651.                             /* Cast the magic spell of Boyer-Moore... */
  652.  
  653.                         if(LastSearchPosition < 1)
  654.                             SearchPosition = LineWidth - (PatternWidth - 1);
  655.                         else
  656.                             SearchPosition = LastSearchPosition;
  657.  
  658.                         do
  659.                         {
  660.                             PatternIndex = 0;
  661.                             LineIndex = SearchPosition - 1;
  662.  
  663.                             while(PatternIndex < PatternWidth && Pattern[PatternIndex] == ToUpper(Line[LineIndex]))
  664.                             {
  665.                                 LineIndex++;
  666.                                 PatternIndex++;
  667.                             }
  668.  
  669.                             SearchPosition -= Distance[ToUpper(Line[SearchPosition - 1])];
  670.  
  671.                             if(PatternIndex == PatternWidth)
  672.                             {
  673.                                 Info -> FoundX    = LineIndex - PatternWidth;
  674.                                 Info -> FoundY    = i;
  675.                                 Info -> Index    = SearchPosition;
  676.  
  677.                                 return(i);
  678.                             }
  679.                         }
  680.                         while(SearchPosition > 0);
  681.                     }
  682.  
  683.                     LastSearchPosition = 0;
  684.                 }
  685.             }
  686.         }
  687.         else
  688.         {
  689.             if(Info -> Forward)
  690.             {
  691.                     /* Update the search positions. */
  692.  
  693.                 if(Info -> FoundY == -1)
  694.                 {
  695.                     Info -> FoundX        = 0;
  696.                     Info -> FoundY        = 0;
  697.                     LastSearchPosition    = 0;
  698.                 }
  699.                 else
  700.                 {
  701.                         /* Proceed to the next line. */
  702.  
  703.                     if(!(LastSearchPosition = Info -> Index))
  704.                         Info -> FoundY = (Info -> FoundY + 1) % Lines;
  705.                 }
  706.  
  707.                     /* Run down the buffer. */
  708.  
  709.                 for(i = Info -> FoundY ; i < Lines ; i++)
  710.                 {
  711.                     Line = BufferLines[i];
  712.  
  713.                         /* Is there anything to search for? */
  714.  
  715.                     if((LineWidth = Line[-1]) >= PatternWidth)
  716.                     {
  717.                             /* Where are we to start searching? */
  718.  
  719.                         if(LastSearchPosition)
  720.                             SearchPosition = LastSearchPosition;
  721.                         else
  722.                             SearchPosition = PatternWidth;
  723.  
  724.                         do
  725.                         {
  726.                                 /* How many line characters
  727.                                  * match the pattern?
  728.                                  */
  729.  
  730.                             PatternIndex    = PatternWidth - 1;
  731.                             LineIndex    = SearchPosition - 1;
  732.  
  733.                             while(PatternIndex >= 0 && Pattern[PatternIndex] == Line[LineIndex])
  734.                             {
  735.                                 LineIndex--;
  736.                                 PatternIndex--;
  737.                             }
  738.  
  739.                                 /* Update the line search index
  740.                                  * for subsequent searches.
  741.                                  */
  742.  
  743.                             SearchPosition += Distance[Line[SearchPosition - 1]];
  744.  
  745.                                 /* Found the pattern? */
  746.  
  747.                             if(PatternIndex < 0)
  748.                             {
  749.                                     /* Store the position. */
  750.  
  751.                                 Info -> FoundX    = LineIndex + 1;
  752.                                 Info -> FoundY    = i;
  753.  
  754.                                     /* Remember column to start
  755.                                      * next search attempt at.
  756.                                      */
  757.  
  758.                                 if(SearchPosition <= LineWidth)
  759.                                     Info -> Index = SearchPosition;
  760.                                 else
  761.                                     Info -> Index = 0;
  762.  
  763.                                 return(i);
  764.                             }
  765.                         }
  766.                         while(SearchPosition <= LineWidth);
  767.                     }
  768.  
  769.                         /* Reset search column. */
  770.  
  771.                     LastSearchPosition = 0;
  772.                 }
  773.             }
  774.             else
  775.             {
  776.                     /* Update the search positions. */
  777.  
  778.                 if(Info -> FoundY == -1)
  779.                 {
  780.                     Info -> FoundX        = 0;
  781.                     Info -> FoundY        = Lines - 1;
  782.                     LastSearchPosition    = 0;
  783.                 }
  784.                 else
  785.                 {
  786.                     if((LastSearchPosition = Info -> Index) < 1)
  787.                     {
  788.                         if(Info -> FoundY)
  789.                             Info -> FoundY--;
  790.                         else
  791.                             Info -> FoundY = Lines - 1;
  792.                     }
  793.                 }
  794.  
  795.                     /* Run down the buffer. */
  796.  
  797.                 for(i = Info -> FoundY ; i >= 0 ; i--)
  798.                 {
  799.                     Line = BufferLines[i];
  800.  
  801.                         /* Is there anything to search for? */
  802.  
  803.                     if((LineWidth = Line[-1]) >= PatternWidth)
  804.                     {
  805.                             /* Cast the magic spell of Boyer-Moore... */
  806.  
  807.                         if(LastSearchPosition < 1)
  808.                             SearchPosition = LineWidth - (PatternWidth - 1);
  809.                         else
  810.                             SearchPosition = LastSearchPosition;
  811.  
  812.                         do
  813.                         {
  814.                             PatternIndex = 0;
  815.                             LineIndex = SearchPosition - 1;
  816.  
  817.                             while(PatternIndex < PatternWidth && Pattern[PatternIndex] == Line[LineIndex])
  818.                             {
  819.                                 LineIndex++;
  820.                                 PatternIndex++;
  821.                             }
  822.  
  823.                             SearchPosition -= Distance[Line[SearchPosition - 1]];
  824.  
  825.                             if(PatternIndex == PatternWidth)
  826.                             {
  827.                                 Info -> FoundX    = LineIndex - PatternWidth;
  828.                                 Info -> FoundY    = i;
  829.                                 Info -> Index    = SearchPosition;
  830.  
  831.                                 return(i);
  832.                             }
  833.                         }
  834.                         while(SearchPosition > 0);
  835.                     }
  836.  
  837.                     LastSearchPosition = 0;
  838.                 }
  839.             }
  840.         }
  841.     }
  842.  
  843.     return(-1);
  844. }
  845.  
  846. STATIC ULONG __asm __saveds
  847. HistoryFunc(register __a0 struct Hook *Hook,register __a1 STRPTR NewString)
  848. {
  849.     struct List *List = (struct List *)Hook -> h_Data;
  850.  
  851.     if(NewString)
  852.     {
  853.         struct Node *Node = CreateNode(NewString);
  854.  
  855.         if(Node)
  856.             AddTail(List,Node);
  857.         else
  858.             return(FALSE);
  859.     }
  860.     else
  861.     {
  862.         struct Node *Node = RemHead(List);
  863.  
  864.         FreeNode(Node);
  865.     }
  866.  
  867.     return(TRUE);
  868. }
  869.  
  870.     /* GetSearchString():
  871.      *
  872.      *    Prompt the user for a search string.
  873.      */
  874.  
  875. BYTE __regargs
  876. GetSearchString(struct Window *ParentWindow,BYTE *ParentTerminated,STRPTR Buffer,struct Hook *HistoryHook,BYTE *Forward,BYTE *IgnoreCase)
  877. {
  878.     enum    {    GAD_OK=1,GAD_CANCEL,GAD_STRING };
  879.  
  880.     struct LayoutHandle    *Handle;
  881.     BYTE             Success = FALSE;
  882.  
  883.     if(HistoryHook)
  884.         HistoryHook -> h_Entry = (HOOKFUNC)HistoryFunc;
  885.  
  886.     if(Handle = LT_CreateHandleTags(ParentWindow -> WScreen,
  887.         LH_LocaleHook,    &LocaleHook,
  888.     TAG_DONE))
  889.     {
  890.         UBYTE         LocalBuffer[256];
  891.         struct Window    *Window;
  892.  
  893.         LocalBuffer[0] = 0;
  894.  
  895.         LT_New(Handle,
  896.             LA_Type,    VERTICAL_KIND,
  897.         TAG_DONE);
  898.         {
  899.             LT_New(Handle,
  900.                 LA_Type,    HORIZONTAL_KIND,
  901.                 LA_LabelText,    LocaleString(MSG_TERMBUFFER_ENTER_SEARCH_STRING_TXT),
  902.             TAG_DONE);
  903.             {
  904.                 LT_New(Handle,
  905.                     LA_Type,    VERTICAL_KIND,
  906.                 TAG_DONE);
  907.                 {
  908.                     LT_New(Handle,
  909.                         LA_Type,        STRING_KIND,
  910.                         LA_LabelID,        MSG_V36_0788,
  911.                         LA_STRPTR,        LocalBuffer,
  912.                         LA_Chars,        30,
  913.                         LA_ID,            GAD_STRING,
  914.                         LAST_HistoryLines,    MAX(Config -> CaptureConfig -> SearchHistory,1),
  915.                         LAST_HistoryHook,    HistoryHook,
  916.                         GTST_MaxChars,        255,
  917.                     TAG_DONE);
  918.  
  919.                     LT_EndGroup(Handle);
  920.                 }
  921.  
  922.                 LT_New(Handle,
  923.                     LA_Type,    VERTICAL_KIND,
  924.                 TAG_DONE);
  925.                 {
  926.                     LT_New(Handle,
  927.                         LA_Type,    CHECKBOX_KIND,
  928.                         LA_LabelID,    MSG_TERMBUFFER_SEARCH_FORWARD_TXT,
  929.                         LA_BYTE,    Forward,
  930.                     TAG_DONE);
  931.  
  932.                     LT_New(Handle,
  933.                         LA_Type,    CHECKBOX_KIND,
  934.                         LA_LabelID,    MSG_TEXTBUFFER_IGNORE_CASE_GAD,
  935.                         LA_BYTE,    IgnoreCase,
  936.                     TAG_DONE);
  937.  
  938.                     LT_EndGroup(Handle);
  939.                 }
  940.  
  941.                 LT_EndGroup(Handle);
  942.             }
  943.  
  944.             LT_New(Handle,
  945.                 LA_Type,    VERTICAL_KIND,
  946.             TAG_DONE);
  947.             {
  948.                 LT_New(Handle,LA_Type,XBAR_KIND,LAXB_FullSize,TRUE,TAG_DONE);
  949.  
  950.                 LT_EndGroup(Handle);
  951.             }
  952.  
  953.             LT_New(Handle,LA_Type,HORIZONTAL_KIND,
  954.                 LAGR_SameSize,    TRUE,
  955.                 LAGR_Spread,    TRUE,
  956.             TAG_DONE);
  957.             {
  958.                 LT_New(Handle,
  959.                     LA_Type,    BUTTON_KIND,
  960.                     LA_LabelID,    MSG_TERMXPR_OKAY_GAD,
  961.                     LA_ID,        GAD_OK,
  962.                     LABT_ReturnKey,    TRUE,
  963.                     LABT_ExtraFat,    TRUE,
  964.                 TAG_DONE);
  965.  
  966.                 LT_New(Handle,
  967.                     LA_Type,    BUTTON_KIND,
  968.                     LA_LabelID,    MSG_GLOBAL_CANCEL_GAD,
  969.                     LA_ID,        GAD_CANCEL,
  970.                     LABT_EscKey,    TRUE,
  971.                     LABT_ExtraFat,    TRUE,
  972.                 TAG_DONE);
  973.  
  974.                 LT_EndGroup(Handle);
  975.             }
  976.  
  977.             LT_EndGroup(Handle);
  978.         }
  979.  
  980.         if(Window = LT_Layout(Handle,LocaleString(MSG_TERMBUFFER_ENTER_SEARCH_STRING_TXT),NULL,0,0,IDCMP_CLOSEWINDOW,0,
  981.             LAWN_HelpHook,        &GuideHook,
  982.             WA_DepthGadget,        TRUE,
  983.             WA_CloseGadget,        TRUE,
  984.             WA_DragBar,        TRUE,
  985.             WA_RMBTrap,        TRUE,
  986.             WA_Activate,        TRUE,
  987.         TAG_DONE))
  988.         {
  989.             struct IntuiMessage    *Message;
  990.             BOOLEAN             Done = FALSE;
  991.             ULONG             MsgClass,
  992.                          MsgQualifier;
  993.             UWORD             MsgCode;
  994.             struct Gadget        *MsgGadget;
  995.             ULONG             SignalSet;
  996.  
  997.             if(ParentTerminated)
  998.                 ClrSignal(SIG_TOFRONT | SIG_KILL);
  999.             else
  1000.                 ClrSignal(SIG_BREAK);
  1001.  
  1002.             LT_Activate(Handle,GAD_STRING);
  1003.  
  1004.             do
  1005.             {
  1006.                 if(ParentTerminated)
  1007.                 {
  1008.                     SignalSet = Wait(SIG_TOFRONT | SIG_KILL | PORTMASK(Window -> UserPort));
  1009.  
  1010.                     if(SignalSet & SIG_TOFRONT)
  1011.                         BumpWindow(Window);
  1012.  
  1013.                     if(SignalSet & SIG_KILL)
  1014.                         *ParentTerminated = Done = TRUE;
  1015.                 }
  1016.                 else
  1017.                 {
  1018.                     SignalSet = Wait(PORTMASK(Window -> UserPort) | SIG_BREAK);
  1019.  
  1020.                     if(SignalSet & SIG_BREAK)
  1021.                         Done = TRUE;
  1022.                 }
  1023.  
  1024.                 while(Message = (struct IntuiMessage *)GT_GetIMsg(Window -> UserPort))
  1025.                 {
  1026.                     MsgClass    = Message -> Class;
  1027.                     MsgQualifier    = Message -> Qualifier;
  1028.                     MsgCode        = Message -> Code;
  1029.                     MsgGadget    = (struct Gadget *)Message -> IAddress;
  1030.  
  1031.                     GT_ReplyIMsg(Message);
  1032.  
  1033.                     LT_HandleInput(Handle,MsgQualifier,&MsgClass,&MsgCode,&MsgGadget);
  1034.  
  1035.                     if(MsgClass == IDCMP_CLOSEWINDOW)
  1036.                         Done = TRUE;
  1037.  
  1038.                     if(MsgClass == IDCMP_GADGETUP)
  1039.                     {
  1040.                         switch(MsgGadget -> GadgetID)
  1041.                         {
  1042.                             case GAD_STRING:
  1043.  
  1044.                                 if(MsgCode == '\r')
  1045.                                 {
  1046.                                     if(LocalBuffer[0])
  1047.                                     {
  1048.                                         strcpy(Buffer,LocalBuffer);
  1049.  
  1050.                                         Success = TRUE;
  1051.  
  1052.                                         LT_PressButton(Handle,GAD_OK);
  1053.                                     }
  1054.                                     else
  1055.                                         LT_PressButton(Handle,GAD_CANCEL);
  1056.  
  1057.                                     Done = TRUE;
  1058.                                 }
  1059.  
  1060.                                 break;
  1061.  
  1062.                             case GAD_OK:
  1063.  
  1064.                                 if(LocalBuffer[0])
  1065.                                 {
  1066.                                     strcpy(Buffer,LocalBuffer);
  1067.  
  1068.                                     Success = TRUE;
  1069.                                 }
  1070.  
  1071.                                 Done = TRUE;
  1072.  
  1073.                                 break;
  1074.  
  1075.                             case GAD_CANCEL:
  1076.  
  1077.                                 Done = TRUE;
  1078.  
  1079.                                 break;
  1080.                         }
  1081.                     }
  1082.                 }
  1083.             }
  1084.             while(!Done);
  1085.         }
  1086.  
  1087.         LT_DeleteHandle(Handle);
  1088.     }
  1089.  
  1090.     return(Success);
  1091. }
  1092.